package com.xukun.changgou.auth.config;

import com.xukun.changgou.auth.filter.BaseLoginFilter;
import com.xukun.changgou.auth.filter.BaseTokenFilter;
import com.xukun.changgou.auth.handler.BaseAccessDeniedHandler;
import com.xukun.changgou.auth.handler.BaseAuthenticationEntryPoint;
import com.xukun.changgou.auth.handler.BaseLogoutSuccessHandler;
import com.xukun.changgou.auth.service.BaseUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Author xukun
 * @Date 2021-06-02 15:52
 * @Description
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class BaseWebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定义未登录处理器
     */
    @Autowired
    private BaseAuthenticationEntryPoint authenticationEntryPoint;

    /**
     * 自定义访问受限处理器
     */
    @Autowired
    private BaseAccessDeniedHandler accessDeniedHandler;

    /**
     * 自定义退出登录处理器
     */
    @Autowired
    private BaseLogoutSuccessHandler logoutSuccessHandler;

    /**
     * 自定义具体的登录验证
     *
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService() {
        return new BaseUserDetailsServiceImpl();
    }

    /**
     * 注入密码加密器
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 自定义登录过滤器
     */
    @Bean
    public BaseLoginFilter loginFilter() throws Exception {
        BaseLoginFilter loginFilter = new BaseLoginFilter();
        loginFilter.setAuthenticationManager(authenticationManager());
        return loginFilter;
    }

    /**
     * 自定义token过滤器
     */
    @Bean
    public BaseTokenFilter tokenFilter() throws Exception {
        return new BaseTokenFilter(authenticationManager());
    }

    /**
     * 为了让登陆认证的时候，抛出UsernameNotFoundException异常
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        //默认为true,不抛出
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 关闭csrf验证(防止跨站请求伪造攻击)
        http.csrf().disable().cors();
        //登录异常
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)//未登录
                .accessDeniedHandler(accessDeniedHandler);//无访问权限
        //无状态session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //拦截所有请求
        http.authorizeRequests()
//                .antMatchers("/auth/login", "/auth/logout").permitAll()
                .anyRequest().authenticated();

        http.logout().logoutUrl("/auth/logout")
                .logoutSuccessHandler(logoutSuccessHandler);

        //自定义登录过滤器和token验证过滤器
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilter(tokenFilter());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(authenticationProvider());
    }

    /**
     * 控制静态资源的访问，比如swagger-ui
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/swagger-ui.html",
                "/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
                "/swagger-resources/**",
                "/webjars/**"
        );
    }

}
